Datascience for Macroeconomics using WDI

Introduction

AI and Datascience

Evidence based, data based thinking

Macroeconomics

The study of the entire economy of a region, a country, or the entire world

World Development Indicator

Open social science database.

Open Data and Public Data

Datascience and Artificial Intelligence

  • Computer Resources

  • Data

    • Big Data

    • Open and Public Data

Q. Explain ‘Open Data’ and ‘Public Data’, and their differences. AI: Poe Assistant.

A. AI Poe Assistant. (Poe.com)

“Open data” and “public data” are related concepts that refer to different aspects of data accessibility and usage.

Open Data: Open data refers to the idea that certain data should be freely available to the public, without restrictions on access, usage, or redistribution. Open data is typically released in a machine-readable format, such as CSV, JSON, or XML, and is accompanied by an open license that allows anyone to use, reuse, and distribute the data for any purpose. The goal of open data is to promote transparency, collaboration, and innovation by enabling individuals, organizations, and communities to analyze and build upon the data.

Open data often includes government data, scientific research data, public records, and other datasets that are deemed to be of public interest. Governments, international organizations, and various institutions actively promote the release of open data to foster accountability, drive economic growth, and empower citizens to make informed decisions.

Public Data: Public data, on the other hand, refers to any data that is accessible or available to the public. It is a broader term that encompasses both open data and other types of data that may have certain restrictions on access or usage. Public data can include information that is freely and openly available, as well as data that is accessible through specific channels, such as public libraries, government agencies, or subscription-based services.

Public data can include a wide range of information, such as government reports, census data, legal documents, financial statements, and more. While public data may be accessible to the public, it does not necessarily guarantee the same level of openness, usability, or freedom as open data. Public data may have limitations on its usage, copyright restrictions, or conditions imposed by the data provider.

In summary, open data specifically refers to data that is freely accessible, usable, and redistributable without restrictions, often accompanied by an open license. Public data, on the other hand, is a broader term that includes both open data and other data that may have varying degrees of accessibility and usage restrictions.

World Bank on Open Data for Open Government

Visit Open Government Data Toolkit.

R on RStudio

Posit Cloud

Datascience Workflow

The image above is from R4DS(2e) by Hadley Wickham, Mine Çetinkaya-Rundel and Garrett Grolemund
The image above is from R4DS(2e) by Hadley Wickham, Mine Çetinkaya-Rundel and Garrett Grolemund

First Datascience

Setup

Step 1. Install packages if necessary.

install.packages("tidyverse")
install.packages("WDI")

Step 2. Load packages.

library(tidyverse)
library(WDI)

Step 3. Create a data directory for the first time.

dir.create("data")

Step 4. Set ‘System Language’ to be English, recommended.

Sys.setenv(LANG = "en")

Importing GDP Data

The following code chunk is to download GDP data with the following indicator code.

WDI indicator: NY.GDP.MKTP.PP.KD

df_gdp <- WDI(indicator = "NY.GDP.MKTP.PP.KD")

N.B. There are many GDP related data in WDI.

To avoid the internet traffic, save the data and reuse it.

CSV: comma separated values, a text format of a data.

write_csv(df_gdp, "data/gdp.csv")

Run codes above only once to download and write the data into the data directory.

df_gdp <- read_csv("data/gdp.csv")
Rows: 16758 Columns: 5── Column specification ───────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): country, iso2c, iso3c
dbl (2): year, NY.GDP.MKTP.PP.KD
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Viewing Data

head: print the first 6 rows by default

head(df_gdp)

2.561800e+12 is in scientific notation, i.e., 2.561800 \(\times10^{12} = 2,562,800,000,000\).

str: display the structure of an object

str(df_gdp)
spc_tbl_ [16,758 × 5] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ country          : chr [1:16758] "Africa Eastern and Southern" "Africa Eastern and Southern" "Africa Eastern and Southern" "Africa Eastern and Southern" ...
 $ iso2c            : chr [1:16758] "ZH" "ZH" "ZH" "ZH" ...
 $ iso3c            : chr [1:16758] "AFE" "AFE" "AFE" "AFE" ...
 $ year             : num [1:16758] 2022 2021 2020 2019 2018 ...
 $ NY.GDP.MKTP.PP.KD: num [1:16758] 2.56e+12 2.47e+12 2.37e+12 2.43e+12 2.38e+12 ...
 - attr(*, "spec")=
  .. cols(
  ..   country = col_character(),
  ..   iso2c = col_character(),
  ..   iso3c = col_character(),
  ..   year = col_double(),
  ..   NY.GDP.MKTP.PP.KD = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 

summary: display the summary of an object

summary(df_gdp)

In RNotebook, the following also displays the first 1000 rows of the data in the paged format.

df_gdp

Transformation

|> is called a pipe operator and the following is same as

filter(df_gdp, country == COUNTRY) .

filter : Keep rows that match a condition

COUNTRY <- "Japan"
df_gdp |> filter(country == COUNTRY)

Visualization

GDP of Japan

ggplot + geom_line: A tidyverse function of draw a line graph

aes(year, NY.GDP.MKTP.PP.KD) : aesthetic mapping sending year to x-axis and NY.GDP.MKTP.PP.KD to y-axis

COUNTRY <- "Japan"
df_gdp |> filter(country == COUNTRY) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD)) + geom_line()

Let’s delete the rows with missing values using drop_na(NY.GDP.MKTP.PP.KD). A transformation.

COUNTRY <- "Japan"
df_gdp |> filter(country == COUNTRY) |> drop_na(NY.GDP.MKTP.PP.KD) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD)) + geom_line()

GDP of the World

COUNTRY <- "World"
df_gdp |> filter(country == COUNTRY) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD)) + geom_line()

Exercise.

  1. Delete the missing data of the GDP of the World mimicking the one of Japan.
  2. Write down your observations and questions.
COUNTRY <- "World"
df_gdp |> filter(country == COUNTRY) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD)) + geom_line()

Observations and Questions

  • e.g. The GDP of the world is continuously increasing since 1990.

GDP of the countries

By country names

COUNTRIES <- c("Japan", "China", "India", "United Kingdom", "United States", "Germany", "France")
df_gdp |> filter(country %in% COUNTRIES) |> drop_na(NY.GDP.MKTP.PP.KD) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD, color = country)) + geom_line()

ISO2C <- c("JP", "CN", "ID", "UK", "US", "DE", "FR")
df_gdp |> filter(iso2c %in% ISO2C) |> drop_na(NY.GDP.MKTP.PP.KD) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD, color = iso2c)) + geom_line()

Exercise.

What happens if you replace color = iso2c at the bottom of the code above with colour = iso2c , color = country , col = country ?

List of Countries and iso2c

df_gdp |> distinct(country, iso2c)

Exercise.

Set COUNTRIES and/or ISO2C to draw line graphs of GDP.

COUNTRIES <- c() # surround the country name with quotation marks, and use a comma as a separator
df_gdp |> filter(country %in% COUNTRIES) |> drop_na(NY.GDP.MKTP.PP.KD) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD, color = country)) + geom_line()
ISO2C <- c() # surround the iso2c code with quotation marks, and use a comma as a separator
df_gdp |> filter(iso2c %in% ISO2C) |> drop_na(NY.GDP.MKTP.PP.KD) |>
  ggplot(aes(year, NY.GDP.MKTP.PP.KD, color = iso2c)) + geom_line()

World Development Indicator

Find Indicator Codes

  1. World Bank Home Page

    • World Development Indicators: Link

    • World Bank Open Data: Link

    • WDI Statistical Tables: Link

  2. Excel Files

    • Data Catalogues: Link Download Excel File
  3. API Search

WDIsearch(string = "gdp", field = "name")
WDIsearch(string = "NY.GDP.MKTP.PP.KD", field = "indicator")

GDP and GDP per Capita

  1. GDP, PPP (constant 2017 international $): NY.GDP.MKTP.PP.KD

  2. Population, total: SP.POP.TOTL

  3. Calculate GDP per Capita

    • GDP per capita, PPP (constant 2017 international $): NY.GDP.PCAP.PP.KD
  • GDP, PPP (constant 2017 international $) PPP GDP is gross domestic product converted to international dollars using purchasing power parity rates. An international dollar has the same purchasing power over GDP as the U.S. dollar has in the United States. GDP is the sum of gross value added by all resident producers in the country plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources. Data are in constant 2017 international dollars. ID: NY.GDP.MKTP.PP.KD

  • Population, total Total population is based on the de facto definition of population, which counts all residents regardless of legal status or citizenship. The values shown are midyear estimates. ID: SP.POP.TOTL

df_gdppcap <- WDI(indicator = c(gdp = "NY.GDP.MKTP.PP.KD", pop = "SP.POP.TOTL"), extra = TRUE)
write_csv(df_gdppcap, "data/gdppcap.csv")
df_dgppcap <- read_csv("data/gdppcap.csv")
COUNTRY <- "World"
df_gdppcap |> filter(country == COUNTRY) |>
  ggplot(aes(year, gdp)) + geom_line()

COUNTRY <- "World"
df_gdppcap |> filter(country == COUNTRY) |>
  ggplot(aes(year, pop)) + geom_line()

Exercise.

Write your observations.

GDP Per Capita

df_gdppcap2 <- df_gdppcap |> drop_na(pop) |> 
  mutate(gdppcap = gdp/pop, .before = gdp)
df_gdppcap2
COUNTRY <- "World"
df_gdppcap2 |> filter(country == COUNTRY) |>
  ggplot(aes(year, gdppcap)) + geom_line()

Check against GDP per capita, PPP

df_gdppcap_check <- WDI(indicator = c(PCAP = "NY.GDP.PCAP.PP.KD", gdp = "NY.GDP.MKTP.PP.KD", pop = "SP.POP.TOTL"), extra = TRUE) |>
  drop_na(pop) |>
  mutate(gdppcap = gdp/pop, .before = gdp)
write_csv(df_gdppcap_check, "data/gdppcap_check.csv")
df_gdppcap_check <- read_csv("data/gdppcap_check.csv")
Rows: 16665 Columns: 16── Column specification ───────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (7): country, iso2c, iso3c, region, capital, income, lending
dbl  (7): year, PCAP, gdppcap, gdp, pop, longitude, latitude
lgl  (1): status
date (1): lastupdated
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_gdppcap_check |> drop_na(gdppcap) |> mutate(near = near(PCAP, gdppcap)) |> 
  summarize(n = n(), sum(near))

Visualization

Two useful questions.

  1. What type of variation occurs within my variables?

  2. What type of covariation occurs between my variables?

Variation 1. Histogram

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdp) |> 
  ggplot(aes(gdp)) + geom_histogram()

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdppcap) |> 
  ggplot(aes(gdppcap)) + geom_histogram()

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdp) |> 
  ggplot(aes(gdp)) + geom_histogram() + scale_x_log10()

Exercise.

Change bins, i.e., geom_histogram(bins = 20), etc.

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdp) |> 
  ggplot(aes(gdp)) + geom_histogram(bins = 20) + scale_x_log10()

Exercise.

Create a similar histogram by using scale_x_log10() and adjusting the number of bins.

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdppcap) |> 
  ggplot(aes(gdppcap)) + geom_histogram() + scale_x_log10()

Variation 2. Boxplot

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdppcap) |> 
  ggplot(aes(gdppcap)) + geom_boxplot() + scale_x_log10()

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdppcap) |> 
  filter(income != "Aggregates") |> 
  ggplot(aes(gdppcap, income, fill = income)) + geom_boxplot() + scale_x_log10() +
  theme(legend.position = "none")

df_gdppcap2 |> filter(year == 2020) |> drop_na(gdp) |> 
  filter(income != "Aggregates") |> 
  ggplot(aes(gdp, region, fill = region)) + geom_boxplot() + scale_x_log10() +
  theme(legend.position = "none")

df_gdppcap2 |> filter(year == 2020, region !="Aggregates") |> drop_na(gdp, pop) |> 
  ggplot(aes(pop, gdp, color = region)) + geom_point() + 
  scale_x_log10() + scale_y_log10()

install.packages("plotly")
library(plotly)
test <- df_gdppcap2 |> filter(year == 2020, region !="Aggregates") |> drop_na(gdp, pop) |> 
  ggplot(aes(color = country, shape = region, pop, gdp)) + geom_point() + 
  scale_x_log10() + scale_y_log10() + theme(legend.position = "none")
test |> ggplotly()
Warning: The shape palette can deal with a maximum of 6 discrete values because more than 6
becomes difficult to discriminate; you have 7. Consider specifying shapes manually if
you must have them.

CO2 Emissions Per Capita vs GDP Per Capita

  1. CO2 emissions (metric tons per capita): EN.ATM.CO2E.PC

  2. GDP per capita, PPP (constant 2017 international $): NY.GDP.PCAP.PP.KD

  • CO2 emissions (metric tons per capita) Carbon dioxide emissions are those stemming from the burning of fossil fuels and the manufacture of cement. They include carbon dioxide produced during consumption of solid, liquid, and gas fuels and gas flaring. EN.ATM.CO2E.PC

  • GDP per capita, PPP (constant 2017 international $) GDP per capita based on purchasing power parity (PPP). PPP GDP is gross domestic product converted to international dollars using purchasing power parity rates. An international dollar has the same purchasing power over GDP as the U.S. dollar has in the United States. GDP at purchaser’s prices is the sum of gross value added by all resident producers in the country plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources. Data are in constant 2017 international dollars. ID: NY.GDP.PCAP.PP.KD

df_co2gdp <- WDI(indicator = c(co2pcap = "EN.ATM.CO2E.PC", gdppcap = "NY.GDP.PCAP.PP.KD"), extra = TRUE)
write_csv(df_co2gdp, "data/co2gdp.csv")
df_co2gdp <- read_csv("data/co2gdp.csv")
COUNTRY <- "World"
df_co2gdp |> filter(country == COUNTRY) |>
  ggplot(aes(year, co2pcap)) + geom_line()

df_co2gdp |> filter(year == 2020) |> drop_na(co2pcap) |>
  ggplot(aes(gdppcap, co2pcap)) + geom_point()

df_co2gdp |> filter(year == 2020) |> drop_na(co2pcap) |>
  ggplot(aes(gdppcap, co2pcap)) + geom_point() +
  scale_x_log10() + scale_y_log10()

df_co2gdp |> filter(year == 2020) |> 
  drop_na(gdppcap, co2pcap) |>
  ggplot(aes(gdppcap, co2pcap)) + geom_point() +
  geom_smooth(method = "lm", formula = 'y~x', se = FALSE) +
  scale_x_log10() + scale_y_log10()

df_co2gdp |> lm(co2pcap~gdppcap, data = _) |> summary()

Call:
lm(formula = co2pcap ~ gdppcap, data = df_co2gdp)

Residuals:
     Min       1Q   Median       3Q      Max 
-15.7271  -0.9824  -0.5867   0.6631  27.3247 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 4.349e-01  4.635e-02   9.383   <2e-16 ***
gdppcap     2.357e-04  1.955e-06 120.573   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.875 on 6909 degrees of freedom
  (9847 observations deleted due to missingness)
Multiple R-squared:  0.6779,    Adjusted R-squared:  0.6778 
F-statistic: 1.454e+04 on 1 and 6909 DF,  p-value: < 2.2e-16

School Enrollment vs GDP Per Capita

  1. School enrollment, secondary (% gross): SE.SEC.ENRR

  2. GDP per capita, PPP (constant 2017 international $): NY.GDP.PCAP.PP.KD

  • School enrollment, secondary (% gross) Gross enrollment ratio is the ratio of total enrollment, regardless of age, to the population of the age group that officially corresponds to the level of education shown. Secondary education completes the provision of basic education that began at the primary level, and aims at laying the foundations for lifelong learning and human development, by offering more subject- or skill-oriented instruction using more specialized teachers. SE.SEC.ENRR

  • GDP per capita, PPP (constant 2017 international $) GDP per capita based on purchasing power parity (PPP). PPP GDP is gross domestic product converted to international dollars using purchasing power parity rates. An international dollar has the same purchasing power over GDP as the U.S. dollar has in the United States. GDP at purchaser’s prices is the sum of gross value added by all resident producers in the country plus any product taxes and minus any subsidies not included in the value of the products. It is calculated without making deductions for depreciation of fabricated assets or for depletion and degradation of natural resources. Data are in constant 2017 international dollars. ID: NY.GDP.PCAP.PP.KD

df_secgdp <- WDI(indicator = c(sec = "SE.SEC.ENRR", gdppcap = "NY.GDP.PCAP.PP.KD"), extra = TRUE)
write_csv(df_secgdp, "data/secgdp.csv")
df_secgdp <- read_csv("data/secgdp.csv")
COUNTRY <- "World"
df_secgdp |> filter(country == COUNTRY) |>
  ggplot(aes(year, sec)) + geom_line()

df_secgdp |> filter(year == 2020) |> drop_na(sec) |>
  ggplot(aes(gdppcap, sec)) + geom_point()

df_secgdp |> filter(year == 2020) |> drop_na(gdppcap, sec) |>
  ggplot(aes(gdppcap, sec)) + geom_point() +
  scale_x_log10()

df_secgdp |> filter(year == 2020) |> drop_na(gdppcap, sec) |>
  ggplot(aes(gdppcap, sec)) + geom_point() +
  geom_smooth(method = "lm", formula = 'y~x', se = FALSE) +
  scale_x_log10()

df_secgdp |> lm(sec~gdppcap, data = _) |> summary()

Call:
lm(formula = sec ~ gdppcap, data = df_secgdp)

Residuals:
     Min       1Q   Median       3Q      Max 
-120.077  -15.876    3.865   17.126   85.165 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 5.678e+01  4.372e-01  129.88   <2e-16 ***
gdppcap     9.878e-04  1.682e-05   58.71   <2e-16 ***
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 23.43 on 5366 degrees of freedom
  (11390 observations deleted due to missingness)
Multiple R-squared:  0.3911,    Adjusted R-squared:  0.391 
F-statistic:  3447 on 1 and 5366 DF,  p-value: < 2.2e-16

References

  1. R for Data Science (2e): Link. The First Edition: Link.

  2. Posit Primers: Link.

  3. Cheat Sheet: Link.

  4. Input data set: Historical country-level Gross Domestic Product (GDP): Link

LS0tCnRpdGxlOiAiR1MgTWFjcm8gMjAyMyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBEYXRhc2NpZW5jZSBmb3IgTWFjcm9lY29ub21pY3MgdXNpbmcgV0RJCgojIyBJbnRyb2R1Y3Rpb24KCiMjIyBBSSBhbmQgRGF0YXNjaWVuY2UKCkV2aWRlbmNlIGJhc2VkLCBkYXRhIGJhc2VkIHRoaW5raW5nCgojIyMgTWFjcm9lY29ub21pY3MKClRoZSBzdHVkeSBvZiB0aGUgZW50aXJlIGVjb25vbXkgb2YgYSByZWdpb24sIGEgY291bnRyeSwgb3IgdGhlIGVudGlyZSB3b3JsZAoKIyMjIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcgoKT3BlbiBzb2NpYWwgc2NpZW5jZSBkYXRhYmFzZS4KCiMjIE9wZW4gRGF0YSBhbmQgUHVibGljIERhdGEKCkRhdGFzY2llbmNlIGFuZCBBcnRpZmljaWFsIEludGVsbGlnZW5jZQoKLSAgIENvbXB1dGVyIFJlc291cmNlcwoKLSAgIERhdGEKCiAgICAtICAgQmlnIERhdGEKCiAgICAtICAgT3BlbiBhbmQgUHVibGljIERhdGEKCj4gUS4gRXhwbGFpbiAnT3BlbiBEYXRhJyBhbmQgJ1B1YmxpYyBEYXRhJywgYW5kIHRoZWlyIGRpZmZlcmVuY2VzLiBBSTogUG9lIEFzc2lzdGFudC4KPgo+IEEuIEFJIFBvZSBBc3Npc3RhbnQuIChbUG9lLmNvbV0oaHR0cHM6Ly9wb2UuY29tKSkKPgo+ICJPcGVuIGRhdGEiIGFuZCAicHVibGljIGRhdGEiIGFyZSByZWxhdGVkIGNvbmNlcHRzIHRoYXQgcmVmZXIgdG8gZGlmZmVyZW50IGFzcGVjdHMgb2YgZGF0YSBhY2Nlc3NpYmlsaXR5IGFuZCB1c2FnZS4KPgo+IE9wZW4gRGF0YTogT3BlbiBkYXRhIHJlZmVycyB0byB0aGUgaWRlYSB0aGF0IGNlcnRhaW4gZGF0YSBzaG91bGQgYmUgZnJlZWx5IGF2YWlsYWJsZSB0byB0aGUgcHVibGljLCB3aXRob3V0IHJlc3RyaWN0aW9ucyBvbiBhY2Nlc3MsIHVzYWdlLCBvciByZWRpc3RyaWJ1dGlvbi4gT3BlbiBkYXRhIGlzIHR5cGljYWxseSByZWxlYXNlZCBpbiBhIG1hY2hpbmUtcmVhZGFibGUgZm9ybWF0LCBzdWNoIGFzIENTViwgSlNPTiwgb3IgWE1MLCBhbmQgaXMgYWNjb21wYW5pZWQgYnkgYW4gb3BlbiBsaWNlbnNlIHRoYXQgYWxsb3dzIGFueW9uZSB0byB1c2UsIHJldXNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUgZGF0YSBmb3IgYW55IHB1cnBvc2UuIFRoZSBnb2FsIG9mIG9wZW4gZGF0YSBpcyB0byBwcm9tb3RlIHRyYW5zcGFyZW5jeSwgY29sbGFib3JhdGlvbiwgYW5kIGlubm92YXRpb24gYnkgZW5hYmxpbmcgaW5kaXZpZHVhbHMsIG9yZ2FuaXphdGlvbnMsIGFuZCBjb21tdW5pdGllcyB0byBhbmFseXplIGFuZCBidWlsZCB1cG9uIHRoZSBkYXRhLgoKPiBPcGVuIGRhdGEgb2Z0ZW4gaW5jbHVkZXMgZ292ZXJubWVudCBkYXRhLCBzY2llbnRpZmljIHJlc2VhcmNoIGRhdGEsIHB1YmxpYyByZWNvcmRzLCBhbmQgb3RoZXIgZGF0YXNldHMgdGhhdCBhcmUgZGVlbWVkIHRvIGJlIG9mIHB1YmxpYyBpbnRlcmVzdC4gR292ZXJubWVudHMsIGludGVybmF0aW9uYWwgb3JnYW5pemF0aW9ucywgYW5kIHZhcmlvdXMgaW5zdGl0dXRpb25zIGFjdGl2ZWx5IHByb21vdGUgdGhlIHJlbGVhc2Ugb2Ygb3BlbiBkYXRhIHRvIGZvc3RlciBhY2NvdW50YWJpbGl0eSwgZHJpdmUgZWNvbm9taWMgZ3Jvd3RoLCBhbmQgZW1wb3dlciBjaXRpemVucyB0byBtYWtlIGluZm9ybWVkIGRlY2lzaW9ucy4KPgo+IFB1YmxpYyBEYXRhOiBQdWJsaWMgZGF0YSwgb24gdGhlIG90aGVyIGhhbmQsIHJlZmVycyB0byBhbnkgZGF0YSB0aGF0IGlzIGFjY2Vzc2libGUgb3IgYXZhaWxhYmxlIHRvIHRoZSBwdWJsaWMuIEl0IGlzIGEgYnJvYWRlciB0ZXJtIHRoYXQgZW5jb21wYXNzZXMgYm90aCBvcGVuIGRhdGEgYW5kIG90aGVyIHR5cGVzIG9mIGRhdGEgdGhhdCBtYXkgaGF2ZSBjZXJ0YWluIHJlc3RyaWN0aW9ucyBvbiBhY2Nlc3Mgb3IgdXNhZ2UuIFB1YmxpYyBkYXRhIGNhbiBpbmNsdWRlIGluZm9ybWF0aW9uIHRoYXQgaXMgZnJlZWx5IGFuZCBvcGVubHkgYXZhaWxhYmxlLCBhcyB3ZWxsIGFzIGRhdGEgdGhhdCBpcyBhY2Nlc3NpYmxlIHRocm91Z2ggc3BlY2lmaWMgY2hhbm5lbHMsIHN1Y2ggYXMgcHVibGljIGxpYnJhcmllcywgZ292ZXJubWVudCBhZ2VuY2llcywgb3Igc3Vic2NyaXB0aW9uLWJhc2VkIHNlcnZpY2VzLgo+Cj4gUHVibGljIGRhdGEgY2FuIGluY2x1ZGUgYSB3aWRlIHJhbmdlIG9mIGluZm9ybWF0aW9uLCBzdWNoIGFzIGdvdmVybm1lbnQgcmVwb3J0cywgY2Vuc3VzIGRhdGEsIGxlZ2FsIGRvY3VtZW50cywgZmluYW5jaWFsIHN0YXRlbWVudHMsIGFuZCBtb3JlLiBXaGlsZSBwdWJsaWMgZGF0YSBtYXkgYmUgYWNjZXNzaWJsZSB0byB0aGUgcHVibGljLCBpdCBkb2VzIG5vdCBuZWNlc3NhcmlseSBndWFyYW50ZWUgdGhlIHNhbWUgbGV2ZWwgb2Ygb3Blbm5lc3MsIHVzYWJpbGl0eSwgb3IgZnJlZWRvbSBhcyBvcGVuIGRhdGEuIFB1YmxpYyBkYXRhIG1heSBoYXZlIGxpbWl0YXRpb25zIG9uIGl0cyB1c2FnZSwgY29weXJpZ2h0IHJlc3RyaWN0aW9ucywgb3IgY29uZGl0aW9ucyBpbXBvc2VkIGJ5IHRoZSBkYXRhIHByb3ZpZGVyLgo+Cj4gSW4gc3VtbWFyeSwgb3BlbiBkYXRhIHNwZWNpZmljYWxseSByZWZlcnMgdG8gZGF0YSB0aGF0IGlzIGZyZWVseSBhY2Nlc3NpYmxlLCB1c2FibGUsIGFuZCByZWRpc3RyaWJ1dGFibGUgd2l0aG91dCByZXN0cmljdGlvbnMsIG9mdGVuIGFjY29tcGFuaWVkIGJ5IGFuIG9wZW4gbGljZW5zZS4gUHVibGljIGRhdGEsIG9uIHRoZSBvdGhlciBoYW5kLCBpcyBhIGJyb2FkZXIgdGVybSB0aGF0IGluY2x1ZGVzIGJvdGggb3BlbiBkYXRhIGFuZCBvdGhlciBkYXRhIHRoYXQgbWF5IGhhdmUgdmFyeWluZyBkZWdyZWVzIG9mIGFjY2Vzc2liaWxpdHkgYW5kIHVzYWdlIHJlc3RyaWN0aW9ucy4KCiMjIyMgV29ybGQgQmFuayBvbiBPcGVuIERhdGEgZm9yIE9wZW4gR292ZXJubWVudAoKVmlzaXQgW09wZW4gR292ZXJubWVudCBEYXRhIFRvb2xraXRdKGh0dHBzOi8vb3BlbmRhdGF0b29sa2l0LndvcmxkYmFuay5vcmcvZW4vZGF0YS9vcGVuZGF0YXRvb2xraXQvaG9tZSkuCgojIyBSIG9uIFJTdHVkaW8KCiMjIyBQb3NpdCBDbG91ZAoKLSAgIFBvc2l0LmNsb3VkOiA8aHR0cHM6Ly9wb3NpdC5jbG91ZC8+CgogICAgLSAgIFtQb3NpdCBQcmltZXJzXShodHRwczovL3Bvc2l0LmNsb3VkL2xlYXJuL3ByaW1lcnMpCgogICAgLSAgIFtDaGVhdHNoZWV0c10oaHR0cHM6Ly9wb3NpdC5jbG91ZC9sZWFybi9jaGVhdC1zaGVldHMpCgotICAgU2hhcmVkIFByb2plY3Q6IDxodHRwczovL3Bvc2l0LmNsb3VkL2NvbnRlbnQvNTUzOTc2Mz4KCi0gICBDcmVhdGUgWW91ciBDb3B5IGFuZCBEb3dubG9hZCBpdC4KCiMjIERhdGFzY2llbmNlIFdvcmtmbG93CgohWypUaGUgaW1hZ2UgYWJvdmUgaXMgZnJvbSBbUjREUygyZSldKGh0dHBzOi8vcjRkcy5oYWRsZXkubnopIGJ5IEhhZGxleSBXaWNraGFtLCBNaW5lIMOHZXRpbmtheWEtUnVuZGVsIGFuZCBHYXJyZXR0IEdyb2xlbXVuZCpdKGRhdGEvZGF0YS1zY2llbmNlLnBuZykKCiMjIEZpcnN0IERhdGFzY2llbmNlCgojIyMgU2V0dXAKClN0ZXAgMS4gSW5zdGFsbCBwYWNrYWdlcyBpZiBuZWNlc3NhcnkuCgpgYGB7ciBldmFsID0gRkFMU0V9Cmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCmluc3RhbGwucGFja2FnZXMoIldESSIpCmBgYAoKU3RlcCAyLiBMb2FkIHBhY2thZ2VzLgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFdESSkKYGBgCgpTdGVwIDMuIENyZWF0ZSBhIGRhdGEgZGlyZWN0b3J5IGZvciB0aGUgZmlyc3QgdGltZS4KCmBgYHtyIGNyZWF0ZS1kaXJzLCBldmFsID0gRkFMU0V9CmRpci5jcmVhdGUoImRhdGEiKQpgYGAKClN0ZXAgNC4gU2V0ICdTeXN0ZW0gTGFuZ3VhZ2UnIHRvIGJlIEVuZ2xpc2gsIHJlY29tbWVuZGVkLgoKYGBge3IgZXZhbCA9IEZBTFNFfQpTeXMuc2V0ZW52KExBTkcgPSAiZW4iKQpgYGAKCiMjIyBJbXBvcnRpbmcgR0RQIERhdGEKClRoZSBmb2xsb3dpbmcgY29kZSBjaHVuayBpcyB0byBkb3dubG9hZCBHRFAgZGF0YSB3aXRoIHRoZSBmb2xsb3dpbmcgaW5kaWNhdG9yIGNvZGUuCgpXREkgaW5kaWNhdG9yOiBOWS5HRFAuTUtUUC5QUC5LRAoKYGBge3IgY2FjaGUgPSBUUlVFLCBldmFsID0gRkFMU0V9CmRmX2dkcCA8LSBXREkoaW5kaWNhdG9yID0gIk5ZLkdEUC5NS1RQLlBQLktEIikKYGBgCgpOLkIuIFRoZXJlIGFyZSBtYW55IEdEUCByZWxhdGVkIGRhdGEgaW4gV0RJLgoKVG8gYXZvaWQgdGhlIGludGVybmV0IHRyYWZmaWMsIHNhdmUgdGhlIGRhdGEgYW5kIHJldXNlIGl0LgoKQ1NWOiBjb21tYSBzZXBhcmF0ZWQgdmFsdWVzLCBhIHRleHQgZm9ybWF0IG9mIGEgZGF0YS4KCmBgYHtyIGV2YWwgPSBGQUxTRX0Kd3JpdGVfY3N2KGRmX2dkcCwgImRhdGEvZ2RwLmNzdiIpCmBgYAoKUnVuIGNvZGVzIGFib3ZlIG9ubHkgb25jZSB0byBkb3dubG9hZCBhbmQgd3JpdGUgdGhlIGRhdGEgaW50byB0aGUgZGF0YSBkaXJlY3RvcnkuCgpgYGB7cn0KZGZfZ2RwIDwtIHJlYWRfY3N2KCJkYXRhL2dkcC5jc3YiKQpgYGAKCiMjIyBWaWV3aW5nIERhdGEKCmBoZWFkYDogcHJpbnQgdGhlIGZpcnN0IDYgcm93cyBieSBkZWZhdWx0CgpgYGB7cn0KaGVhZChkZl9nZHApCmBgYAoKMi41NjE4MDBlKzEyIGlzIGluIHNjaWVudGlmaWMgbm90YXRpb24sIGkuZS4sIDIuNTYxODAwICRcdGltZXMxMF57MTJ9ID0gMiw1NjIsODAwLDAwMCwwMDAkLgoKYHN0cmA6IGRpc3BsYXkgdGhlIHN0cnVjdHVyZSBvZiBhbiBvYmplY3QKCmBgYHtyfQpzdHIoZGZfZ2RwKQpgYGAKCmBzdW1tYXJ5YDogZGlzcGxheSB0aGUgc3VtbWFyeSBvZiBhbiBvYmplY3QKCmBgYHtyfQpzdW1tYXJ5KGRmX2dkcCkKYGBgCgpJbiBSTm90ZWJvb2ssIHRoZSBmb2xsb3dpbmcgYWxzbyBkaXNwbGF5cyB0aGUgZmlyc3QgMTAwMCByb3dzIG9mIHRoZSBkYXRhIGluIHRoZSBwYWdlZCBmb3JtYXQuCgpgYGB7ciBldmFsID0gRkFMU0V9CmRmX2dkcApgYGAKCiMjIyBUcmFuc2Zvcm1hdGlvbgoKYHw+YCBpcyBjYWxsZWQgYSBwaXBlIG9wZXJhdG9yIGFuZCB0aGUgZm9sbG93aW5nIGlzIHNhbWUgYXMKCmBmaWx0ZXIoZGZfZ2RwLCBjb3VudHJ5ID09IENPVU5UUlkpYCAuCgpgZmlsdGVyYCA6IEtlZXAgcm93cyB0aGF0IG1hdGNoIGEgY29uZGl0aW9uCgpgYGB7cn0KQ09VTlRSWSA8LSAiSmFwYW4iCmRmX2dkcCB8PiBmaWx0ZXIoY291bnRyeSA9PSBDT1VOVFJZKQpgYGAKCiMjIyBWaXN1YWxpemF0aW9uCgojIyMjIEdEUCBvZiBKYXBhbgoKYGdncGxvdCArIGdlb21fbGluZWA6IEEgdGlkeXZlcnNlIGZ1bmN0aW9uIG9mIGRyYXcgYSBsaW5lIGdyYXBoCgpgYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktEKWAgOiBhZXN0aGV0aWMgbWFwcGluZyBzZW5kaW5nIHllYXIgdG8geC1heGlzIGFuZCBgTlkuR0RQLk1LVFAuUFAuS0RgIHRvIHktYXhpcwoKYGBge3J9CkNPVU5UUlkgPC0gIkphcGFuIgpkZl9nZHAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktEKSkgKyBnZW9tX2xpbmUoKQpgYGAKCkxldCdzIGRlbGV0ZSB0aGUgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzIHVzaW5nIGRyb3BfbmEoTlkuR0RQLk1LVFAuUFAuS0QpLiBBIHRyYW5zZm9ybWF0aW9uLgoKYGBge3J9CkNPVU5UUlkgPC0gIkphcGFuIgpkZl9nZHAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4gZHJvcF9uYShOWS5HRFAuTUtUUC5QUC5LRCkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktEKSkgKyBnZW9tX2xpbmUoKQpgYGAKCiMjIyMgR0RQIG9mIHRoZSBXb3JsZAoKYGBge3J9CkNPVU5UUlkgPC0gIldvcmxkIgpkZl9nZHAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktEKSkgKyBnZW9tX2xpbmUoKQpgYGAKCiMjIyMgRXhlcmNpc2UuCgoxLiAgRGVsZXRlIHRoZSBtaXNzaW5nIGRhdGEgb2YgdGhlIEdEUCBvZiB0aGUgV29ybGQgbWltaWNraW5nIHRoZSBvbmUgb2YgSmFwYW4uCjIuICBXcml0ZSBkb3duIHlvdXIgb2JzZXJ2YXRpb25zIGFuZCBxdWVzdGlvbnMuCgpgYGB7ciBldmFsID0gRkFMU0V9CkNPVU5UUlkgPC0gIldvcmxkIgpkZl9nZHAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktEKSkgKyBnZW9tX2xpbmUoKQpgYGAKCioqT2JzZXJ2YXRpb25zIGFuZCBRdWVzdGlvbnMqKgoKLSAgIGUuZy4gVGhlIEdEUCBvZiB0aGUgd29ybGQgaXMgY29udGludW91c2x5IGluY3JlYXNpbmcgc2luY2UgMTk5MC4KCi0gICAKCiMjIyMgR0RQIG9mIHRoZSBjb3VudHJpZXMKCkJ5IGNvdW50cnkgbmFtZXMKCmBgYHtyfQpDT1VOVFJJRVMgPC0gYygiSmFwYW4iLCAiQ2hpbmEiLCAiSW5kaWEiLCAiVW5pdGVkIEtpbmdkb20iLCAiVW5pdGVkIFN0YXRlcyIsICJHZXJtYW55IiwgIkZyYW5jZSIpCmRmX2dkcCB8PiBmaWx0ZXIoY291bnRyeSAlaW4lIENPVU5UUklFUykgfD4gZHJvcF9uYShOWS5HRFAuTUtUUC5QUC5LRCkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktELCBjb2xvciA9IGNvdW50cnkpKSArIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CklTTzJDIDwtIGMoIkpQIiwgIkNOIiwgIklEIiwgIlVLIiwgIlVTIiwgIkRFIiwgIkZSIikKZGZfZ2RwIHw+IGZpbHRlcihpc28yYyAlaW4lIElTTzJDKSB8PiBkcm9wX25hKE5ZLkdEUC5NS1RQLlBQLktEKSB8PgogIGdncGxvdChhZXMoeWVhciwgTlkuR0RQLk1LVFAuUFAuS0QsIGNvbG9yID0gaXNvMmMpKSArIGdlb21fbGluZSgpCmBgYAoKIyMjIyBFeGVyY2lzZS4KCldoYXQgaGFwcGVucyBpZiB5b3UgcmVwbGFjZSBgY29sb3IgPSBpc28yY2AgYXQgdGhlIGJvdHRvbSBvZiB0aGUgY29kZSBhYm92ZSB3aXRoIGBjb2xvdXIgPSBpc28yY2AgLCBgY29sb3IgPSBjb3VudHJ5YCAsIGBjb2wgPSBjb3VudHJ5YCA/CgojIyMjIExpc3Qgb2YgQ291bnRyaWVzIGFuZCBpc28yYwoKYGBge3J9CmRmX2dkcCB8PiBkaXN0aW5jdChjb3VudHJ5LCBpc28yYykKYGBgCgojIyMjICoqRXhlcmNpc2UuKioKClNldCBDT1VOVFJJRVMgYW5kL29yIElTTzJDIHRvIGRyYXcgbGluZSBncmFwaHMgb2YgR0RQLgoKYGBge3IgZXZhbCA9IEZBTFNFfQpDT1VOVFJJRVMgPC0gYygpICMgc3Vycm91bmQgdGhlIGNvdW50cnkgbmFtZSB3aXRoIHF1b3RhdGlvbiBtYXJrcywgYW5kIHVzZSBhIGNvbW1hIGFzIGEgc2VwYXJhdG9yCmRmX2dkcCB8PiBmaWx0ZXIoY291bnRyeSAlaW4lIENPVU5UUklFUykgfD4gZHJvcF9uYShOWS5HRFAuTUtUUC5QUC5LRCkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIE5ZLkdEUC5NS1RQLlBQLktELCBjb2xvciA9IGNvdW50cnkpKSArIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CklTTzJDIDwtIGMoKSAjIHN1cnJvdW5kIHRoZSBpc28yYyBjb2RlIHdpdGggcXVvdGF0aW9uIG1hcmtzLCBhbmQgdXNlIGEgY29tbWEgYXMgYSBzZXBhcmF0b3IKZGZfZ2RwIHw+IGZpbHRlcihpc28yYyAlaW4lIElTTzJDKSB8PiBkcm9wX25hKE5ZLkdEUC5NS1RQLlBQLktEKSB8PgogIGdncGxvdChhZXMoeWVhciwgTlkuR0RQLk1LVFAuUFAuS0QsIGNvbG9yID0gaXNvMmMpKSArIGdlb21fbGluZSgpCmBgYAoKIyMgV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9yCgojIyMgRmluZCBJbmRpY2F0b3IgQ29kZXMKCjEuICBXb3JsZCBCYW5rIEhvbWUgUGFnZQoKICAgIC0gICBXb3JsZCBEZXZlbG9wbWVudCBJbmRpY2F0b3JzOiBbTGlua10oaHR0cHM6Ly9kYXRhdG9waWNzLndvcmxkYmFuay5vcmcvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycy8pCgogICAgLSAgIFdvcmxkIEJhbmsgT3BlbiBEYXRhOiBbTGlua10oaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcpCgogICAgLSAgIFdESSBTdGF0aXN0aWNhbCBUYWJsZXM6IFtMaW5rXShodHRwczovL3dkaS53b3JsZGJhbmsub3JnL3RhYmxlcykKCjIuICBFeGNlbCBGaWxlcwoKICAgIC0gICBEYXRhIENhdGFsb2d1ZXM6IFtMaW5rXShodHRwczovL2RhdGFjYXRhbG9nLndvcmxkYmFuay5vcmcvc2VhcmNoL2RhdGFzZXQvMDAzNzcxMi9Xb3JsZC1EZXZlbG9wbWVudC1JbmRpY2F0b3JzKSBEb3dubG9hZCBFeGNlbCBGaWxlCgozLiAgQVBJIFNlYXJjaAoKYGBge3J9CldESXNlYXJjaChzdHJpbmcgPSAiZ2RwIiwgZmllbGQgPSAibmFtZSIpCmBgYAoKYGBge3J9CldESXNlYXJjaChzdHJpbmcgPSAiTlkuR0RQLk1LVFAuUFAuS0QiLCBmaWVsZCA9ICJpbmRpY2F0b3IiKQpgYGAKCiMjIEdEUCBhbmQgR0RQIHBlciBDYXBpdGEKCjEuICBHRFAsIFBQUCAoY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIFwkKTogTlkuR0RQLk1LVFAuUFAuS0QKCjIuICBQb3B1bGF0aW9uLCB0b3RhbDogU1AuUE9QLlRPVEwKCjMuICBDYWxjdWxhdGUgR0RQIHBlciBDYXBpdGEKCiAgICAtICAgR0RQIHBlciBjYXBpdGEsIFBQUCAoY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIFwkKTogTlkuR0RQLlBDQVAuUFAuS0QKCi0gICBHRFAsIFBQUCAoY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIFwkKSBQUFAgR0RQIGlzIGdyb3NzIGRvbWVzdGljIHByb2R1Y3QgY29udmVydGVkIHRvIGludGVybmF0aW9uYWwgZG9sbGFycyB1c2luZyBwdXJjaGFzaW5nIHBvd2VyIHBhcml0eSByYXRlcy4gQW4gaW50ZXJuYXRpb25hbCBkb2xsYXIgaGFzIHRoZSBzYW1lIHB1cmNoYXNpbmcgcG93ZXIgb3ZlciBHRFAgYXMgdGhlIFUuUy4gZG9sbGFyIGhhcyBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gR0RQIGlzIHRoZSBzdW0gb2YgZ3Jvc3MgdmFsdWUgYWRkZWQgYnkgYWxsIHJlc2lkZW50IHByb2R1Y2VycyBpbiB0aGUgY291bnRyeSBwbHVzIGFueSBwcm9kdWN0IHRheGVzIGFuZCBtaW51cyBhbnkgc3Vic2lkaWVzIG5vdCBpbmNsdWRlZCBpbiB0aGUgdmFsdWUgb2YgdGhlIHByb2R1Y3RzLiBJdCBpcyBjYWxjdWxhdGVkIHdpdGhvdXQgbWFraW5nIGRlZHVjdGlvbnMgZm9yIGRlcHJlY2lhdGlvbiBvZiBmYWJyaWNhdGVkIGFzc2V0cyBvciBmb3IgZGVwbGV0aW9uIGFuZCBkZWdyYWRhdGlvbiBvZiBuYXR1cmFsIHJlc291cmNlcy4gRGF0YSBhcmUgaW4gY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIGRvbGxhcnMuIElEOiBOWS5HRFAuTUtUUC5QUC5LRAoKLSAgIFBvcHVsYXRpb24sIHRvdGFsIFRvdGFsIHBvcHVsYXRpb24gaXMgYmFzZWQgb24gdGhlIGRlIGZhY3RvIGRlZmluaXRpb24gb2YgcG9wdWxhdGlvbiwgd2hpY2ggY291bnRzIGFsbCByZXNpZGVudHMgcmVnYXJkbGVzcyBvZiBsZWdhbCBzdGF0dXMgb3IgY2l0aXplbnNoaXAuIFRoZSB2YWx1ZXMgc2hvd24gYXJlIG1pZHllYXIgZXN0aW1hdGVzLiBJRDogU1AuUE9QLlRPVEwKCmBgYHtyIGNhY2hlID0gVFJVRX0KZGZfZ2RwcGNhcCA8LSBXREkoaW5kaWNhdG9yID0gYyhnZHAgPSAiTlkuR0RQLk1LVFAuUFAuS0QiLCBwb3AgPSAiU1AuUE9QLlRPVEwiKSwgZXh0cmEgPSBUUlVFKQpgYGAKCmBgYHtyfQp3cml0ZV9jc3YoZGZfZ2RwcGNhcCwgImRhdGEvZ2RwcGNhcC5jc3YiKQpgYGAKCmBgYHtyIGV2YWw9RkFMU0V9CmRmX2RncHBjYXAgPC0gcmVhZF9jc3YoImRhdGEvZ2RwcGNhcC5jc3YiKQpgYGAKCmBgYHtyfQpDT1VOVFJZIDwtICJXb3JsZCIKZGZfZ2RwcGNhcCB8PiBmaWx0ZXIoY291bnRyeSA9PSBDT1VOVFJZKSB8PgogIGdncGxvdChhZXMoeWVhciwgZ2RwKSkgKyBnZW9tX2xpbmUoKQpgYGAKCmBgYHtyfQpDT1VOVFJZIDwtICJXb3JsZCIKZGZfZ2RwcGNhcCB8PiBmaWx0ZXIoY291bnRyeSA9PSBDT1VOVFJZKSB8PgogIGdncGxvdChhZXMoeWVhciwgcG9wKSkgKyBnZW9tX2xpbmUoKQpgYGAKCiMjIyMgRXhlcmNpc2UuCgpXcml0ZSB5b3VyIG9ic2VydmF0aW9ucy4KCiMjIyBHRFAgUGVyIENhcGl0YQoKYGBge3J9CmRmX2dkcHBjYXAyIDwtIGRmX2dkcHBjYXAgfD4gZHJvcF9uYShwb3ApIHw+IAogIG11dGF0ZShnZHBwY2FwID0gZ2RwL3BvcCwgLmJlZm9yZSA9IGdkcCkKYGBgCgpgYGB7cn0KZGZfZ2RwcGNhcDIKYGBgCgpgYGB7cn0KQ09VTlRSWSA8LSAiV29ybGQiCmRmX2dkcHBjYXAyIHw+IGZpbHRlcihjb3VudHJ5ID09IENPVU5UUlkpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBnZHBwY2FwKSkgKyBnZW9tX2xpbmUoKQpgYGAKCiMjIyMgQ2hlY2sgYWdhaW5zdCBHRFAgcGVyIGNhcGl0YSwgUFBQCgpgYGB7ciBldmFsID0gRkFMU0V9CmRmX2dkcHBjYXBfY2hlY2sgPC0gV0RJKGluZGljYXRvciA9IGMoUENBUCA9ICJOWS5HRFAuUENBUC5QUC5LRCIsIGdkcCA9ICJOWS5HRFAuTUtUUC5QUC5LRCIsIHBvcCA9ICJTUC5QT1AuVE9UTCIpLCBleHRyYSA9IFRSVUUpIHw+CiAgZHJvcF9uYShwb3ApIHw+CiAgbXV0YXRlKGdkcHBjYXAgPSBnZHAvcG9wLCAuYmVmb3JlID0gZ2RwKQpgYGAKCmBgYHtyIGV2YWwgPSBGQUxTRX0Kd3JpdGVfY3N2KGRmX2dkcHBjYXBfY2hlY2ssICJkYXRhL2dkcHBjYXBfY2hlY2suY3N2IikKYGBgCgpgYGB7cn0KZGZfZ2RwcGNhcF9jaGVjayA8LSByZWFkX2NzdigiZGF0YS9nZHBwY2FwX2NoZWNrLmNzdiIpCmBgYAoKYGBge3J9CmRmX2dkcHBjYXBfY2hlY2sgfD4gZHJvcF9uYShnZHBwY2FwKSB8PiBtdXRhdGUobmVhciA9IG5lYXIoUENBUCwgZ2RwcGNhcCkpIHw+IAogIHN1bW1hcml6ZShuID0gbigpLCBzdW0obmVhcikpCmBgYAoKIyMjIyBWaXN1YWxpemF0aW9uCgpUd28gdXNlZnVsIHF1ZXN0aW9ucy4KCjEuICBXaGF0IHR5cGUgb2bCoCoqdmFyaWF0aW9uKirCoG9jY3Vyc8KgKip3aXRoaW4qKsKgbXkgdmFyaWFibGVzPwoKMi4gIFdoYXQgdHlwZSBvZsKgKipjb3ZhcmlhdGlvbioqwqBvY2N1cnPCoCoqYmV0d2VlbioqwqBteSB2YXJpYWJsZXM/CgojIyMjIFZhcmlhdGlvbiAxLiBIaXN0b2dyYW0KCmBgYHtyfQpkZl9nZHBwY2FwMiB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKGdkcCkgfD4gCiAgZ2dwbG90KGFlcyhnZHApKSArIGdlb21faGlzdG9ncmFtKCkKYGBgCgpgYGB7cn0KZGZfZ2RwcGNhcDIgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShnZHBwY2FwKSB8PiAKICBnZ3Bsb3QoYWVzKGdkcHBjYXApKSArIGdlb21faGlzdG9ncmFtKCkKYGBgCgpgYGB7cn0KZGZfZ2RwcGNhcDIgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShnZHApIHw+IAogIGdncGxvdChhZXMoZ2RwKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgc2NhbGVfeF9sb2cxMCgpCmBgYAoKIyMjIyBFeGVyY2lzZS4KCkNoYW5nZSBiaW5zLCBpLmUuLCBgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwKWAsIGV0Yy4KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZGZfZ2RwcGNhcDIgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShnZHApIHw+IAogIGdncGxvdChhZXMoZ2RwKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjApICsgc2NhbGVfeF9sb2cxMCgpCmBgYAoKIyMjIyBFeGVyY2lzZS4KCkNyZWF0ZSBhIHNpbWlsYXIgaGlzdG9ncmFtIGJ5IHVzaW5nIGBzY2FsZV94X2xvZzEwKClgIGFuZCBhZGp1c3RpbmcgdGhlIG51bWJlciBvZiBiaW5zLgoKYGBge3IgZXZhbCA9IEZBTFNFfQpkZl9nZHBwY2FwMiB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKGdkcHBjYXApIHw+IAogIGdncGxvdChhZXMoZ2RwcGNhcCkpICsgZ2VvbV9oaXN0b2dyYW0oKSArIHNjYWxlX3hfbG9nMTAoKQpgYGAKCiMjIyMgVmFyaWF0aW9uIDIuIEJveHBsb3QKCmBgYHtyfQpkZl9nZHBwY2FwMiB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKGdkcHBjYXApIHw+IAogIGdncGxvdChhZXMoZ2RwcGNhcCkpICsgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkKYGBgCgpgYGB7cn0KZGZfZ2RwcGNhcDIgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShnZHBwY2FwKSB8PiAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBpbmNvbWUsIGZpbGwgPSBpbmNvbWUpKSArIGdlb21fYm94cGxvdCgpICsgc2NhbGVfeF9sb2cxMCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKYGBge3J9CmRmX2dkcHBjYXAyIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGRyb3BfbmEoZ2RwKSB8PiAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIikgfD4gCiAgZ2dwbG90KGFlcyhnZHAsIHJlZ2lvbiwgZmlsbCA9IHJlZ2lvbikpICsgZ2VvbV9ib3hwbG90KCkgKyBzY2FsZV94X2xvZzEwKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpgYGB7cn0KZGZfZ2RwcGNhcDIgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCwgcmVnaW9uICE9IkFnZ3JlZ2F0ZXMiKSB8PiBkcm9wX25hKGdkcCwgcG9wKSB8PiAKICBnZ3Bsb3QoYWVzKHBvcCwgZ2RwLCBjb2xvciA9IHJlZ2lvbikpICsgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfeF9sb2cxMCgpICsgc2NhbGVfeV9sb2cxMCgpCmBgYAoKYGBge3IgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKdGVzdCA8LSBkZl9nZHBwY2FwMiB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwLCByZWdpb24gIT0iQWdncmVnYXRlcyIpIHw+IGRyb3BfbmEoZ2RwLCBwb3ApIHw+IAogIGdncGxvdChhZXMoY29sb3IgPSBjb3VudHJ5LCBzaGFwZSA9IHJlZ2lvbiwgcG9wLCBnZHApKSArIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX3hfbG9nMTAoKSArIHNjYWxlX3lfbG9nMTAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKdGVzdCB8PiBnZ3Bsb3RseSgpCmBgYAoKIyMgQ08yIEVtaXNzaW9ucyBQZXIgQ2FwaXRhIHZzIEdEUCBQZXIgQ2FwaXRhCgoxLiAgQ08yIGVtaXNzaW9ucyAobWV0cmljIHRvbnMgcGVyIGNhcGl0YSk6IEVOLkFUTS5DTzJFLlBDCgoyLiAgR0RQIHBlciBjYXBpdGEsIFBQUCAoY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIFwkKTogTlkuR0RQLlBDQVAuUFAuS0QKCi0gICBDTzIgZW1pc3Npb25zIChtZXRyaWMgdG9ucyBwZXIgY2FwaXRhKSBDYXJib24gZGlveGlkZSBlbWlzc2lvbnMgYXJlIHRob3NlIHN0ZW1taW5nIGZyb20gdGhlIGJ1cm5pbmcgb2YgZm9zc2lsIGZ1ZWxzIGFuZCB0aGUgbWFudWZhY3R1cmUgb2YgY2VtZW50LiBUaGV5IGluY2x1ZGUgY2FyYm9uIGRpb3hpZGUgcHJvZHVjZWQgZHVyaW5nIGNvbnN1bXB0aW9uIG9mIHNvbGlkLCBsaXF1aWQsIGFuZCBnYXMgZnVlbHMgYW5kIGdhcyBmbGFyaW5nLiBFTi5BVE0uQ08yRS5QQwoKLSAgIEdEUCBwZXIgY2FwaXRhLCBQUFAgKGNvbnN0YW50IDIwMTcgaW50ZXJuYXRpb25hbCBcJCkgR0RQIHBlciBjYXBpdGEgYmFzZWQgb24gcHVyY2hhc2luZyBwb3dlciBwYXJpdHkgKFBQUCkuIFBQUCBHRFAgaXMgZ3Jvc3MgZG9tZXN0aWMgcHJvZHVjdCBjb252ZXJ0ZWQgdG8gaW50ZXJuYXRpb25hbCBkb2xsYXJzIHVzaW5nIHB1cmNoYXNpbmcgcG93ZXIgcGFyaXR5IHJhdGVzLiBBbiBpbnRlcm5hdGlvbmFsIGRvbGxhciBoYXMgdGhlIHNhbWUgcHVyY2hhc2luZyBwb3dlciBvdmVyIEdEUCBhcyB0aGUgVS5TLiBkb2xsYXIgaGFzIGluIHRoZSBVbml0ZWQgU3RhdGVzLiBHRFAgYXQgcHVyY2hhc2VyJ3MgcHJpY2VzIGlzIHRoZSBzdW0gb2YgZ3Jvc3MgdmFsdWUgYWRkZWQgYnkgYWxsIHJlc2lkZW50IHByb2R1Y2VycyBpbiB0aGUgY291bnRyeSBwbHVzIGFueSBwcm9kdWN0IHRheGVzIGFuZCBtaW51cyBhbnkgc3Vic2lkaWVzIG5vdCBpbmNsdWRlZCBpbiB0aGUgdmFsdWUgb2YgdGhlIHByb2R1Y3RzLiBJdCBpcyBjYWxjdWxhdGVkIHdpdGhvdXQgbWFraW5nIGRlZHVjdGlvbnMgZm9yIGRlcHJlY2lhdGlvbiBvZiBmYWJyaWNhdGVkIGFzc2V0cyBvciBmb3IgZGVwbGV0aW9uIGFuZCBkZWdyYWRhdGlvbiBvZiBuYXR1cmFsIHJlc291cmNlcy4gRGF0YSBhcmUgaW4gY29uc3RhbnQgMjAxNyBpbnRlcm5hdGlvbmFsIGRvbGxhcnMuIElEOiBOWS5HRFAuUENBUC5QUC5LRAoKYGBge3IgY2FjaGUgPSBUUlVFfQpkZl9jbzJnZHAgPC0gV0RJKGluZGljYXRvciA9IGMoY28ycGNhcCA9ICJFTi5BVE0uQ08yRS5QQyIsIGdkcHBjYXAgPSAiTlkuR0RQLlBDQVAuUFAuS0QiKSwgZXh0cmEgPSBUUlVFKQpgYGAKCmBgYHtyfQp3cml0ZV9jc3YoZGZfY28yZ2RwLCAiZGF0YS9jbzJnZHAuY3N2IikKYGBgCgpgYGB7ciBldmFsPUZBTFNFfQpkZl9jbzJnZHAgPC0gcmVhZF9jc3YoImRhdGEvY28yZ2RwLmNzdiIpCmBgYAoKYGBge3J9CkNPVU5UUlkgPC0gIldvcmxkIgpkZl9jbzJnZHAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIGNvMnBjYXApKSArIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CmRmX2NvMmdkcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiBkcm9wX25hKGNvMnBjYXApIHw+CiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBjbzJwY2FwKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpgYGB7cn0KZGZfY28yZ2RwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IAogIGRyb3BfbmEoZ2RwcGNhcCwgY28ycGNhcCkgfD4KICBnZ3Bsb3QoYWVzKGdkcHBjYXAsIGNvMnBjYXApKSArIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfeF9sb2cxMCgpICsgc2NhbGVfeV9sb2cxMCgpCmBgYAoKYGBge3J9CmRmX2NvMmdkcCB8PiBmaWx0ZXIoeWVhciA9PSAyMDIwKSB8PiAKICBkcm9wX25hKGdkcHBjYXAsIGNvMnBjYXApIHw+CiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBjbzJwY2FwKSkgKyBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSAneX54Jywgc2UgPSBGQUxTRSkgKwogIHNjYWxlX3hfbG9nMTAoKSArIHNjYWxlX3lfbG9nMTAoKQpgYGAKCmBgYHtyfQpkZl9jbzJnZHAgfD4gbG0oY28ycGNhcH5nZHBwY2FwLCBkYXRhID0gXykgfD4gc3VtbWFyeSgpCmBgYAoKIyMgU2Nob29sIEVucm9sbG1lbnQgdnMgR0RQIFBlciBDYXBpdGEKCjEuICBTY2hvb2wgZW5yb2xsbWVudCwgc2Vjb25kYXJ5ICglIGdyb3NzKTogU0UuU0VDLkVOUlIKCjIuICBHRFAgcGVyIGNhcGl0YSwgUFBQIChjb25zdGFudCAyMDE3IGludGVybmF0aW9uYWwgXCQpOiBOWS5HRFAuUENBUC5QUC5LRAoKLSAgIFNjaG9vbCBlbnJvbGxtZW50LCBzZWNvbmRhcnkgKCUgZ3Jvc3MpIEdyb3NzIGVucm9sbG1lbnQgcmF0aW8gaXMgdGhlIHJhdGlvIG9mIHRvdGFsIGVucm9sbG1lbnQsIHJlZ2FyZGxlc3Mgb2YgYWdlLCB0byB0aGUgcG9wdWxhdGlvbiBvZiB0aGUgYWdlIGdyb3VwIHRoYXQgb2ZmaWNpYWxseSBjb3JyZXNwb25kcyB0byB0aGUgbGV2ZWwgb2YgZWR1Y2F0aW9uIHNob3duLiBTZWNvbmRhcnkgZWR1Y2F0aW9uIGNvbXBsZXRlcyB0aGUgcHJvdmlzaW9uIG9mIGJhc2ljIGVkdWNhdGlvbiB0aGF0IGJlZ2FuIGF0IHRoZSBwcmltYXJ5IGxldmVsLCBhbmQgYWltcyBhdCBsYXlpbmcgdGhlIGZvdW5kYXRpb25zIGZvciBsaWZlbG9uZyBsZWFybmluZyBhbmQgaHVtYW4gZGV2ZWxvcG1lbnQsIGJ5IG9mZmVyaW5nIG1vcmUgc3ViamVjdC0gb3Igc2tpbGwtb3JpZW50ZWQgaW5zdHJ1Y3Rpb24gdXNpbmcgbW9yZSBzcGVjaWFsaXplZCB0ZWFjaGVycy4gU0UuU0VDLkVOUlIKCi0gICBHRFAgcGVyIGNhcGl0YSwgUFBQIChjb25zdGFudCAyMDE3IGludGVybmF0aW9uYWwgXCQpIEdEUCBwZXIgY2FwaXRhIGJhc2VkIG9uIHB1cmNoYXNpbmcgcG93ZXIgcGFyaXR5IChQUFApLiBQUFAgR0RQIGlzIGdyb3NzIGRvbWVzdGljIHByb2R1Y3QgY29udmVydGVkIHRvIGludGVybmF0aW9uYWwgZG9sbGFycyB1c2luZyBwdXJjaGFzaW5nIHBvd2VyIHBhcml0eSByYXRlcy4gQW4gaW50ZXJuYXRpb25hbCBkb2xsYXIgaGFzIHRoZSBzYW1lIHB1cmNoYXNpbmcgcG93ZXIgb3ZlciBHRFAgYXMgdGhlIFUuUy4gZG9sbGFyIGhhcyBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gR0RQIGF0IHB1cmNoYXNlcidzIHByaWNlcyBpcyB0aGUgc3VtIG9mIGdyb3NzIHZhbHVlIGFkZGVkIGJ5IGFsbCByZXNpZGVudCBwcm9kdWNlcnMgaW4gdGhlIGNvdW50cnkgcGx1cyBhbnkgcHJvZHVjdCB0YXhlcyBhbmQgbWludXMgYW55IHN1YnNpZGllcyBub3QgaW5jbHVkZWQgaW4gdGhlIHZhbHVlIG9mIHRoZSBwcm9kdWN0cy4gSXQgaXMgY2FsY3VsYXRlZCB3aXRob3V0IG1ha2luZyBkZWR1Y3Rpb25zIGZvciBkZXByZWNpYXRpb24gb2YgZmFicmljYXRlZCBhc3NldHMgb3IgZm9yIGRlcGxldGlvbiBhbmQgZGVncmFkYXRpb24gb2YgbmF0dXJhbCByZXNvdXJjZXMuIERhdGEgYXJlIGluIGNvbnN0YW50IDIwMTcgaW50ZXJuYXRpb25hbCBkb2xsYXJzLiBJRDogTlkuR0RQLlBDQVAuUFAuS0QKCmBgYHtyIGNhY2hlID0gVFJVRX0KZGZfc2VjZ2RwIDwtIFdESShpbmRpY2F0b3IgPSBjKHNlYyA9ICJTRS5TRUMuRU5SUiIsIGdkcHBjYXAgPSAiTlkuR0RQLlBDQVAuUFAuS0QiKSwgZXh0cmEgPSBUUlVFKQpgYGAKCmBgYHtyfQp3cml0ZV9jc3YoZGZfc2VjZ2RwLCAiZGF0YS9zZWNnZHAuY3N2IikKYGBgCgpgYGB7ciBldmFsPUZBTFNFfQpkZl9zZWNnZHAgPC0gcmVhZF9jc3YoImRhdGEvc2VjZ2RwLmNzdiIpCmBgYAoKYGBge3J9CkNPVU5UUlkgPC0gIldvcmxkIgpkZl9zZWNnZHAgfD4gZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWSkgfD4KICBnZ3Bsb3QoYWVzKHllYXIsIHNlYykpICsgZ2VvbV9saW5lKCkKYGBgCgpgYGB7cn0KZGZfc2VjZ2RwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGRyb3BfbmEoc2VjKSB8PgogIGdncGxvdChhZXMoZ2RwcGNhcCwgc2VjKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpgYGB7cn0KZGZfc2VjZ2RwIHw+IGZpbHRlcih5ZWFyID09IDIwMjApIHw+IGRyb3BfbmEoZ2RwcGNhcCwgc2VjKSB8PgogIGdncGxvdChhZXMoZ2RwcGNhcCwgc2VjKSkgKyBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3hfbG9nMTAoKQpgYGAKCmBgYHtyfQpkZl9zZWNnZHAgfD4gZmlsdGVyKHllYXIgPT0gMjAyMCkgfD4gZHJvcF9uYShnZHBwY2FwLCBzZWMpIHw+CiAgZ2dwbG90KGFlcyhnZHBwY2FwLCBzZWMpKSArIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9ICd5fngnLCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfeF9sb2cxMCgpCmBgYAoKYGBge3J9CmRmX3NlY2dkcCB8PiBsbShzZWN+Z2RwcGNhcCwgZGF0YSA9IF8pIHw+IHN1bW1hcnkoKQpgYGAKCiMjIFJlZmVyZW5jZXMKCjEuICBSIGZvciBEYXRhIFNjaWVuY2UgKDJlKTogW0xpbmtdKGh0dHBzOi8vcjRkcy5oYWRsZXkubnopLiBUaGUgRmlyc3QgRWRpdGlvbjogW0xpbmtdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnopLgoKMi4gIFBvc2l0IFByaW1lcnM6IFtMaW5rXShodHRwczovL3Bvc2l0LmNsb3VkL2xlYXJuL3ByaW1lcnMpLgoKMy4gIENoZWF0IFNoZWV0OiBbTGlua10oaHR0cHM6Ly9wb3NpdC5jbG91ZC9sZWFybi9jaGVhdC1zaGVldHMpLgoKNC4gIElucHV0IGRhdGEgc2V0OiBIaXN0b3JpY2FsIGNvdW50cnktbGV2ZWwgR3Jvc3MgRG9tZXN0aWMgUHJvZHVjdCAoR0RQKTogW0xpbmtdKGh0dHBzOi8vd3d3LmlzaW1pcC5vcmcvZ2V0dGluZ3N0YXJ0ZWQvaW5wdXQtZGF0YS1iaWFzLWFkanVzdG1lbnQvZGV0YWlscy8zMy8pCg==